﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Tema
{
    /// <summary>
    /// Singleton for running the app.
    /// </summary>
    class AppRunner
    {
        private static AppRunner _instance;
        private static int _poolSize = 1;

        // We need 3 different pools because we cannot instantiate an abstract class
        private CarFactory _carFactory = null;

        private List<Client> _clientList = null;

        private AppRunner()
        {
            if (_carFactory == null)
                _carFactory = new CarFactory(_poolSize);

            if (_clientList == null)
                _clientList = new List<Client>();
        }

        public static AppRunner Instance(int poolSize)
        {
            _poolSize = poolSize;

            if (_instance == null)
            {
                _instance = new AppRunner();
            }

            return _instance;
        }

        public void GeneratePools()
        {
            _carFactory.generateCarPools();
            Console.WriteLine("Pools generated with " + _poolSize + " elements.");
        }

        private void PrintOptions()
        {
            Console.WriteLine("\nChoose an option:");
            Console.WriteLine("1. Add a client;");
            Console.WriteLine("2. Add a car;");
            Console.WriteLine("3. Remove a car;");
            Console.WriteLine("4. Print cars;");
            Console.WriteLine("0. Exit.");
        }

        public void Run()
        {
            PrintOptions();
            char option = Console.ReadKey().KeyChar;
            while (option != '0')
            {
                Console.WriteLine();
                switch (option)
                {
                    case '1':
                        addClient();
                        break;
                    case '2':
                        if (_clientList.Count == 0)
                            Console.WriteLine("You must first add a client.");
                        else
                        {
                            // It seems more natural to ask for the client name first
                            bool flag = true;
                            while (flag)
                            {
                                Console.WriteLine("Enter client's name: ");
                                string name = Console.ReadLine();
                                foreach (Client c in _clientList)
                                {
                                    if (c.getName().Equals(name))
                                    {
                                        addCar(c);
                                        flag = false;
                                        break;
                                    }
                                }
                                if (flag)
                                    Console.WriteLine("Client not found. Try again.");
                            }
                        }
                        break;
                    case '3':
                        if (_clientList.Count == 0)
                            Console.WriteLine("You must first add a client.");
                        else
                        {
                            // It seems more natural to ask for the client name first
                            bool flag = true;
                            while (flag)
                            {
                                Console.WriteLine("Enter client's name: ");
                                string name = Console.ReadLine();
                                foreach (Client c in _clientList)
                                {
                                    if (c.getName().Equals(name))
                                    {
                                        removeCar(c);
                                        flag = false;
                                        break;
                                    }
                                }
                                if (flag)
                                    Console.WriteLine("Client not found. Try again.");
                            }
                        }
                        break;
                    case '4':
                        if (_clientList.Count == 0)
                            Console.WriteLine("You must first add a client.");
                        else
                            printCars();
                        break;
                    default:
                        Console.WriteLine("Invalid Option. Try again.");
                        break;
                }

                // DEBUG
                _carFactory.printPoolSizes();

                PrintOptions();
                option = Console.ReadKey().KeyChar;
            }
        }

        private void printCars()
        {
            foreach (Client c in _clientList)
            {
                c.printCars();
            }
        }

        private void removeCar(Client client)
        {
            bool flag = false;
            string name;
            while (!flag)
            {
                Console.WriteLine("Enter car's name: ");
                name = Console.ReadLine();
                AbstractCar car = client.getCar(name);
                if (car != null)
                {
                    client.deleteCar(car);
                    _carFactory.releaseCar(car);
                    flag = true;
                }
                if (!flag)
                    Console.WriteLine("Car not found. Try again.");
            }
        }

        private void addCar(Client client)
        {
            Console.WriteLine("Enter car type: 1 - Coupe; 2 - Mini; 3 - Sedan");
            char option = 'a';
            AbstractCar car = null;
            while (option != '1' && option != '2' && option != '3')
            {
                option = Console.ReadKey().KeyChar;
                Console.WriteLine();
                switch (option)
                {
                    case '1':
                        car = _carFactory.getCarFromPool(1);
                        setUpCar(car, 1);
                        break;
                    case '2':
                        car = _carFactory.getCarFromPool(2);
                        setUpCar(car, 2);
                        break;
                    case '3':
                        car = _carFactory.getCarFromPool(3);
                        setUpCar(car, 3);
                        break;
                    default:
                        Console.WriteLine("Invalid Option. Try again: 1 - Coupe; 2 - Mini; 3 - Sedan");
                        break;
                }
            }
            client.addCar(car);
            Console.WriteLine("\nCar added.");
        }

        private void setUpCar(AbstractCar car, int type)
        {
            Console.WriteLine("Enter name: ");
            car.setName(Console.ReadLine());
            Console.WriteLine("Enter transmission: ");
            car.setTransmission(Console.ReadLine());
            Console.WriteLine("Enter color: ");
            car.setColor(Console.ReadLine());
            string ch1, ch2, ch3;
            switch (type)
            {
                case 1:
                    Console.WriteLine("Enter Characteristics: Convertible (true/false); Doors Number(int); Fuel Type(string)");
                    break;
                case 2:
                    Console.WriteLine("Enter Characteristics: OffRoad (true/false); Trunk Liters(int); Airbag Number(int)");
                    break;
                case 3:
                    Console.WriteLine("Enter Characteristics: Seets number(int); Seets Cover(string); Pistons Number(int)");
                    break;
                default:
                    break;
            }
            ch1 = Console.ReadLine();
            ch2 = Console.ReadLine();
            ch3 = Console.ReadLine();

            car.setCharacteristics(ch1, ch2, ch3);
        }

        private void addClient()
        {
            string name, age;
            int tempAge = 0;
            Console.WriteLine("Enter client's name: ");
            name = Console.ReadLine();
            
            while (tempAge < 18)
            {
                Console.WriteLine("Enter client's age (over 18): ");
                age = Console.ReadLine();
                try
                {
                    tempAge = int.Parse(age);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Invalid age format:" + e.Message);
                }
            }
            
            _clientList.Add(new Client(name, tempAge));
        }
    }
}
